import { getObject, i18n, nmAppLog } from '@app-nextmesh/common/utils';
import {
  ConditionType,
  IMenu,
  ITreeNode,
  TreeNodeMenuId,
  TreeNodeType,
} from '@app-nextmesh/components/types';
import {
  ICollection,
  IComponent,
  IMeshControl,
  IMeshControlBase,
  IResult,
  IShapeInfo,
  ISimulation,
  ITask,
  KeySelectedEntities,
} from '@app-nextmesh/types';
import { checkAllEntitiesExist } from '@app-nextmesh/utils';
import { isArray, isPlainObject } from 'lodash';
import { getAmcaxProp } from '../../components/Forms/components/utils';
import { additionMenu, deletionMenu, separatorMenu } from './commonMenu';
import { getSimulationFormFormat } from './SimulationMenus';

const LeftTreeData = {
  menuData: [
    {
      id: 'menu1',
      items: [additionMenu, separatorMenu, deletionMenu],
    },
    {
      id: 'menu2',
      items: [deletionMenu],
    },
    {
      id: 'menu3',
      items: [additionMenu],
    },
    {
      id: 'menuVisualization',
      items: [
        {
          label: '添加绘图组',
          value: 'additionPlot',
        },
        separatorMenu,
        deletionMenu,
      ],
    },
  ] as IMenu[],
  treeData: [
    {
      id: TreeNodeType.Components,
      label: 'Component',
      type: TreeNodeType.Components,
      iconName: 'IconGeometries',
      action: 'addition',
      menuId: 'geometryGroup',
      children: [],
    },
    {
      id: TreeNodeType.MeshControl,
      label: i18n.t(TreeNodeType.MeshControl),
      iconName: 'IconMesh',
      children: [],
    },
    {
      id: TreeNodeType.Collections,
      label: i18n.t(TreeNodeType.Collections),
      type: TreeNodeType.Collections,
      iconName: 'IconCollections',
      children: [],
    },
    {
      id: TreeNodeType.Simulations,
      label: '仿真设置',
      type: TreeNodeType.Simulations,
      iconName: 'IconSimulations',
      action: 'addition',
      menuId: 'menu3',
      children: [],
    },
    {
      id: TreeNodeType.Tasks,
      label: i18n.t('task'),
      type: TreeNodeType.Tasks,
      iconName: 'IconTask',
      action: 'addition',
      menuId: 'menu3',
      children: [],
    },
    {
      id: TreeNodeType.PostProcess,
      label: '后处理',
      type: TreeNodeType.PostProcess,
      iconName: 'IconVisualizations',
      children: [],
    },
  ] as ITreeNode[],
};
export default LeftTreeData;
const toLocalComponent = (component: IComponent) => {
  const lc = {
    id: component.uuid,
    type: TreeNodeType.Component,
    label: component.name,
    iconName: 'IconGeometry',
    menuId: TreeNodeMenuId.component,
    hasForm: true,
    children: [],
    formData: component,
  };
  return lc;
};
const toLocalMeshControls = (
  meshControl: IMeshControl,
  shapeInfo: Map<string, IShapeInfo>,
) => {
  if (!meshControl) {
    return [];
  }
  const params = meshControl.params || [];
  const children: ITreeNode[] = [];
  const names = Object.keys(params);
  for (const name of names) {
    const items = params[name];
    if (items?.length > 0) {
      items.forEach((item: IMeshControlBase, index: number) => {
        if (item.isGlobal) {
          // 全局的尺寸控制，不添加到树上
          return;
        }
        const entities = item[KeySelectedEntities];
        const allEntitiesExist = checkAllEntitiesExist(entities, shapeInfo);
        children.push({
          id: `${TreeNodeType.MeshControl}-${name}-${index}`,
          label: item.Name,
          type: name, // Distribution | BoundaryLayer | MeshSize
          action: 'normal',
          menuId: 'menu2',
          hasForm: true,
          iconName: !allEntitiesExist && 'IconWarning',
          formData: item,
        });
      });
    }
  }
  return children;
};
const getEmptyMesh = (geometryUuid: string, name = '') => {
  return {
    uuid: '',
    name: name,
    geometryId: geometryUuid,
    params: { elementSize: [], distribution: [] },
    sizing: {},
  };
};

const generateSimulationTree = (
  formData: ISimulation,
  jsonPath: string, // condition.boundaries, 用于从formData中获取对应的值
  formFormat: object,
  key: string,
  jsonFormatPath: string, // 比如： Structural.结构力学N.boundaries
) => {
  // 用jsonPath从formData中获取对应的值，并生成节点
  const nodeId = `${formData.uuid}-${jsonPath}`;
  const nodeData = getObject(formData, jsonPath);
  const amcaxProp = getAmcaxProp(formFormat);
  const node: ITreeNode = {
    id: nodeId,
    label: nodeData?.Name ?? nodeData?.name ?? i18n.t(key),
    type: `${TreeNodeType.Simulation}-${jsonFormatPath}`,
    hasForm: false,
    iconName: `Icon_${key}`,
    menuId: `${TreeNodeMenuId.simuCondition}-${jsonFormatPath}`,
    formData,
    children: [],
  };
  if (!nodeData) {
    // TODO 可能是后来添加的formFormat，在数据中没有这一项
    // 应该按需生成一个默认的数据更新到服务器
    return node;
  }
  if (amcaxProp) {
    // 根据amcaxProp，生成对应的节点及其子节点
    const selfEditKey = amcaxProp.selfEditKey;
    if (selfEditKey !== undefined) {
      node.hasForm = true;
    }
    if (selfEditKey === '') {
      // 自身就是formData，所以必然没有子节点了，直接返回
      return node;
    }
    if (amcaxProp.flatChildren) {
      /**
       * 将子对象的数据展平（如果是数组的话），添加到父节点中
       * 比如form Data：
       * Domain: {
       *   Basic: { // 排除 selfEditKey 字段
       *   },
       *   Boundaries: [...],
       *   Subdomains: [...],
       * }
       */
      const children = Object.keys(nodeData)
        .filter((key) => key !== selfEditKey)
        .flatMap((key) => {
          const subJsonPath = `${jsonPath}.${key}`;
          const subNodeData = nodeData[key];
          const subFormFormat = formFormat[key];
          const subJsonFormatPath = `${jsonFormatPath}.${key}`;
          // TODO 待验证
          if (isArray(subNodeData)) {
            return subNodeData.map((subItem, index) => {
              const key = subItem[ConditionType];
              return generateSimulationTree(
                formData,
                `${subJsonPath}.${index}`,
                subFormFormat,
                key,
                subJsonFormatPath,
              );
            });
          } else {
            return generateSimulationTree(
              formData,
              subJsonPath,
              subFormFormat,
              key,
              subJsonFormatPath,
            );
          }
        });
      node.children = children;
      return node;
    } else {
      let children: ITreeNode[] = [];
      if (isArray(nodeData)) {
        children = nodeData.map((subItem, index) => {
          const subJsonPath = `${jsonPath}.${index}`;
          const key = subItem[ConditionType];
          const subJsonFormatPath = `${jsonFormatPath}.${key}`;
          const subFormFormat = formFormat[key];
          return generateSimulationTree(
            formData,
            subJsonPath,
            subFormFormat,
            key,
            subJsonFormatPath,
          );
        });
      } else {
        children = Object.keys(nodeData)
          .filter((key) => key !== selfEditKey)
          .map((key) => {
            const subJsonPath = `${jsonPath}.${key}`;
            const subFormFormat = formFormat[key];
            const subNodeData = nodeData[key];
            const subJsonFormatPath = `${jsonFormatPath}.${key}`;
            let label = subNodeData.Name ?? subNodeData.name ?? i18n.t(key);
            if (label === undefined) {
              // TODO 用于 CFD-airplane 的表达式,后期可以删除
              if (['string', 'number'].includes(typeof subNodeData.Value)) {
                label = `${key}:${subNodeData.Value}`;
              }
            }
            return generateSimulationTree(
              formData,
              subJsonPath,
              subFormFormat,
              key,
              subJsonFormatPath,
            );
          });
      }

      node.children = children;
      return node;
    }
  } else {
    // 没有amcaxProp,就到根节点了
    if (['string', 'number'].includes(typeof nodeData.Value)) {
      node.label = `${key}:${nodeData.Value}`;
      node.hasForm = true;
    }
  }
  return node;
};

const toLocalSimulation = (simulation: ISimulation) => {
  const simuType = simulation.simuType;
  const simuPlugin = simulation.simuPlugin;
  // 仿真根节点
  const simuRootNode: ITreeNode = {
    id: simulation.uuid,
    type: TreeNodeType.Simulation,
    label: simulation.name,
    action: 'normal',
    menuId: 'menu2',
    hasForm: true,
    iconName: `Icon_${simuType}`,
    formData: simulation,
    children: [],
  };

  const keyCondition = 'condition';
  const condition = simulation[keyCondition];
  // TODO 兼容老版本的 结构力学N 的solver，迭代几个版本之后把去掉
  if (simuPlugin === '结构力学N') {
    const solver = condition?.solver;
    const incrementation = solver?.['Value']?.Incrementation;
    if (isPlainObject(solver) && incrementation) {
      incrementation.name = `${i18n.t('Static')}1`;
      incrementation[ConditionType] = 'Static';
      condition.solver = [incrementation];
    }
  }

  // 通过simuType、simuPlugin 来获取Json Form Format
  const simuFormFormat = getSimulationFormFormat(`${simuType}.${simuPlugin}`);

  Object.keys(simuFormFormat).forEach((key) => {
    simuRootNode.children.push(
      generateSimulationTree(
        simulation,
        `${keyCondition}.${key}`,
        simuFormFormat[key],
        key,
        `${simuType}.${simuPlugin}.${key}`,
      ),
    );
  });
  return simuRootNode;
};
const getEmptySimulation = (): ISimulation => {
  return {
    uuid: '',
    name: '',
    simuType: '',
    simuPlugin: undefined,
  };
};
const toLocalTask = (task: ITask) => {
  const taskNode: ITreeNode = {
    id: task.uuid,
    label: task.name,
    type: TreeNodeType.Task,
    iconName: 'IconResult',
    action: 'normal',
    menuId: 'menu2',
    hasForm: true,
    formData: task,
    children: [],
  };
  if (task.status !== 'CREATED') {
    // 添加运行（监控-monitor）节点
    taskNode.children.push({
      id: task.uuid + '-' + TreeNodeType.TaskMonitor,
      label: '监控',
      type: TreeNodeType.TaskMonitor,
      formData: task,
    });
  }
  return taskNode;
};
const toLocalPlot = (visualization, plot, index) => {
  return {
    id: visualization.uuid + '-Plot-' + index,
    label: plot.name,
    type: TreeNodeType.VisualizationPlot,
    action: 'normal-addition',
    menuId: 'menu2',
    hasForm: true,
    formData: visualization,
    children: [],
  };
};

const toLocalCollections = (
  collections: ICollection[],
  shapeInfo: Map<string, IShapeInfo>,
) => {
  const children = collections?.map<ITreeNode>((item, index) => {
    const entities = item.SelectedEntities;
    const allEntitiesExist = checkAllEntitiesExist(entities, shapeInfo);
    return {
      id: `${TreeNodeType.Collections}-${index}`,
      type: item.Type,
      label: item.Name,
      menuId: 'menu2',
      hasForm: true,
      iconName: !allEntitiesExist && 'IconWarning',
      formData: item,
    };
  });
  return children ?? [];
};

const toLocalResults = (results: IResult[]) => {
  const newR =
    results?.map((item) => {
      return {
        id: item.uuid,
        type: TreeNodeType.Result,
        label: item.name,
        action: 'normal',
        menuId: 'menu2',
        hasForm: true,
        formData: item,
        children: [],
      };
    }) ?? [];
  const resultsNode: ITreeNode = {
    id: 'results',
    label: '结果',
    type: TreeNodeType.Results,
    iconName: 'IconVisualizations',
    // action: 'normal-addition',
    menuId: 'menuResults',
    children: newR,
  };
  return resultsNode;
};
const toLocalVisualization = (visualization) => {
  let plotsItems = [];
  if (visualization.plots) {
    plotsItems = visualization.plots.map(
      (plot: any, index: number): ITreeNode => {
        return toLocalPlot(visualization, plot, index);
      },
    );
  }
  nmAppLog('plotsItems---visualization', plotsItems, visualization);
  return {
    id: visualization.uuid,
    label: visualization.name,
    type: TreeNodeType.Visualization,
    action: 'normal',
    menuId: 'menuVisualization',
    hasForm: true,
    formData: visualization,
    children: [...plotsItems],
  };
};
const toLocalVisualizations = (visualizations) => {
  const vNodes = visualizations?.map((v) => toLocalVisualization(v));

  return {
    id: TreeNodeType.Visualizations,
    label: i18n.t('plot'),
    type: TreeNodeType.Visualizations,
    menuId: 'menu3',
    action: 'addition',
    children: vNodes ?? [],
  };
};
const getEmptyVisualization = (projectUuid, name = '') => {
  return {
    uuid: '',
    name: name,
    project_uuid: projectUuid,
    items: undefined,
  };
};
export {
  getEmptyMesh,
  getEmptySimulation,
  getEmptyVisualization,
  toLocalCollections,
  toLocalComponent,
  toLocalMeshControls,
  toLocalPlot,
  toLocalResults,
  toLocalSimulation,
  toLocalTask,
  toLocalVisualization,
  toLocalVisualizations,
};
